Get Timer Job Status programmatically

The status of a running timer job can checked programmatically with SPRunningJob.Status. The status can be in one of the following states: Scheduled , Initialized , Succeeded, Failed, Retry, Aborted, Pausing, Paused.
If a job definition is not running in a given moment then we can’t get it with SPWebApplication.RunningJobs. In that case we have to get the timer job’s history entries and check with what status has the job ended when it’s been executed.

Below is the code to get the status of a timer job with a given name. If the job is not running then it checks the last timer job history entry. One minute schedule is assumed for this example. Modify it as per your time job schedule.

using Microsoft.SharePoint.Administration;

private SPRunningJobStatus CheckTimerJobsStatus(SPWebApplication webApp, String timerJobName)
{
	SPRunningJobStatus status;
	
	try
	{
		SPRunningJob runningJob = null;
		SPRunningJobCollection jobs = webApp.RunningJobs;
		foreach (SPRunningJob rJob in jobs)
		{
			if (runningJob.JobDefinitionTitle == timerJobName)
			{
				runningJob = rJob;
			}
		}

		if (runningJob != null)
		{
			status = runningJob.Status;
		}
		else
		{
			SPJobDefinitionCollection jobDefs = webApp.JobDefinitions;
			SPJobHistory lastJob = GetLastJobFromHistory(jobDefs, timerJobName);
			if (lastJob != null)
			{
				status = lastJob.Status;
			}
		}
	}
	catch (Exception ex)
	{
		//Hand the exception as fit, depending where you run this code
	}

    return status;
}
		
private SPJobHistory GetLastJobFromHistory(SPJobDefinitionCollection jobDefs, string jobName)
{
	SPJobHistory lastJob = null;
	foreach (SPJobDefinition jobDef in jobDefs)
	{
		if (jobDef.DisplayName == jobName)
		{
			IEnumerable<SPJobHistory> jobHistory = jobDef.HistoryEntries;

			foreach (SPJobHistory jobHistoryItem in jobHistory)
			{
				if (jobHistoryItem.StartTime - jobDef.LastRunTime < new TimeSpan(0, 1, 0))
				{
					lastJob = jobHistoryItem;
					break;
				}
			}
		}
	}
	return lastJob;
}

The account that executes this code should have enough rights on the configuration database otherwise you will get the following error

The EXECUTE permission was denied on the object ‘proc_GetTimerRunningJobs’, database ‘SharePointConfigDBName’, schema ‘dbo’

The farm account already have the required permissions but you may get this error if you run this with another account, even if you run it with elevated privileges.
For example if you run this code in an application page with RunWithElevatedPrivileges block you may get this error because RunWithElevatedPrivileges elevates the current account to the application pool account, but that account may not have enough rights to execute those SQL procedures.
In that case you have two options: 1. impersonate the farm account or 2. go to the configuration database and grand the application pool account EXECUTE permission for the procedures required for this code to run. EXECUTE permission is needed for the following stored procedures in the configuration database:

  • proc_GetTimerRunningJobs
  • proc_GetTimerJobHistory
  • proc_GetTimerJobLastRunTime

Because we should not directly modify the content and configuration databases its better to impersonate the farm account instead of touching the configuration database.

One Response to Get Timer Job Status programmatically

  1. Anonymous says:

    Great article! Very helpful.

    Xiaowen Fei

Leave a comment